package express;

import express.constant.OperatorEnum;

import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;
import java.util.Stack;

/**
 * 表达式计算接口规范
 *
 * @author miweidong
 * @date 2021-08-10 17:49
 */
public interface IExpressCalculate {

    /**
     * 数字栈：用于存储表达式中的各个数字
     */
    Stack<BigDecimal> NUMBERSTACK = new Stack<>();

    /**
     * 符号栈：用于存储运算符和括号
     */
    Stack<String> SYMBOLSTACK = new Stack<>();

    /**
     * 精度保留
     */
    int SCALE = 2;

    /**
     * 表达式计算
     *
     * @param words 表达式序列
     * @return 计算结果
     */
    BigDecimal calculate(List<String> words);

    /**
     * 栈顶运算符与输入运算符优先级比较
     *
     * @param symbol 输入运算符枚举
     * @return 比较结果
     */
    Boolean comparePrimary(OperatorEnum symbol);

    /**
     * 判断字符是否为数字
     *
     * @param operatorEnum 运算符枚举
     * @return 是否数字
     */
    default Boolean isNumber(OperatorEnum operatorEnum) {
        if (Objects.isNull(operatorEnum)) {
            return true;
        }
        switch (operatorEnum) {
            case ADD:
            case SUBTRACT:
            case MULTIPLY:
            case DIVIDE:
            case EQUALS:
            case LEFT_PARENTHESES:
            case RIGHT_PARENTHESES:
                return false;
            default:
                return true;
        }
    }

    /**
     * 两数运算
     *
     * @param a      运算数
     * @param b      运算数
     * @param symbol 操作符枚举
     */
    default void mathematical(BigDecimal a, BigDecimal b, OperatorEnum symbol) {
        switch (symbol) {
            case ADD:
                NUMBERSTACK.push(a.add(b));
                break;
            case SUBTRACT:
                NUMBERSTACK.push(a.subtract(b));
                break;
            case MULTIPLY:
                NUMBERSTACK.push(a.multiply(b));
                break;
            case DIVIDE:
                try {
                    NUMBERSTACK.push(a.divide(b));
                } catch (ArithmeticException e) {
                    // 进行除法出现无限循环小数时，就会抛异常，此处设置精度重新计算
                    NUMBERSTACK.push(a.divide(b, SCALE, BigDecimal.ROUND_HALF_EVEN));
                }
                break;
            default:
                break;
        }
    }

}
